package session

import (
	"dmsv/call"
	"dmsv/fclient"
	"dmsv/ivr"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"sync"
	"time"
)

type SessionStatus string

const (
	SS_STATUS                    SessionStatus = "ss_init"
	SS_STATUS_CREATE             SessionStatus = "ss_create"
	SS_STATUS_ANSWER             SessionStatus = "ss_answer"
	SS_STATUS_DISCCONECT         SessionStatus = "ss_disconnect"
	SS_STATUS_SERVICE_CREATE     SessionStatus = "ss_s_create"
	SS_STATUS_SERVICE_ANSWER     SessionStatus = "ss_s_answer"
	SS_STATUS_SERVICE_DISCCONECT SessionStatus = "ss_s_disconnect"
	SS_STATUS_DESTROY            SessionStatus = "ss_destroy"
)

const (
	SS_DTMF_QUE          = "queue"
	SS_DTMF_SATISFACTION = "satisfaction"
)

type SessionInfo struct {
	sessionId          string
	appId              string
	bDestroy           bool
	bStartSatisfaction bool
	caller             string
	callee             string
	display            string
	serviceId          string
	callType           CallMethod
	uCallId            string //用户callid
	sCallId            string //坐席callId
	record             string
	cmdTime            time.Time
	startTime          time.Time
	answerTime         time.Time
	hangUpTime         time.Time
	destroyTime        time.Time
	leaveMsgTime       time.Time
	enqueTime          time.Time
	queueName          string
	queId              int
	dtmf               string
	satisfaction       string
	hangCount          int //挂机数量
	cmdLock            sync.RWMutex
	CbChan             chan *CallBackData //上层应用消息回调
	command            SessionCommand
	curCmd             string
	curData            interface{}
	evChan             chan interface{}
	nextAction         interface{}
	ivrHandle          ivr.Handle
	call               map[string]*call.CallInfo
	hangUpReason       interface{}
}

//入队时间
func (this *SessionInfo) GetEnQueTime() time.Time {
	return this.enqueTime
}

//更新入队时间
func (this *SessionInfo) UpdateEnQueTime(queId int, name string) {
	if this.enqueTime.IsZero() {
		this.enqueTime = time.Now()
	}
	this.queueName = name
	this.queId = queId
}

func (this *SessionInfo) CallType() CallMethod {
	return this.callType
}

func (this *SessionInfo) SetDisplay(number string) {
	this.display = number
}

func (this *SessionInfo) Callee() string {
	return this.callee
}

func (this *SessionInfo) Caller() string {
	return this.caller
}

func (this *SessionInfo) Display() string {
	return this.display
}

func (this *SessionInfo) GetSessionId() string {
	return this.sessionId
}

func (this *SessionInfo) tryExcuteCommand(cmd SessionCommand) bool {

	this.cmdLock.Lock()
	defer this.cmdLock.Unlock()

	//if this.command == SESSION_COMMAND {
	this.cmdTime = time.Now()
	this.command = cmd
	return true
	//}

	//return false
}

func (this *SessionInfo) sendCbData(evStatus CallEvent) {

	msg := &CallBackData{
		Event: evStatus,
	}

	this.CbChan <- msg
}

func (this *SessionInfo) upDateCommand(cmd SessionCommand) {

	this.cmdLock.Lock()
	defer this.cmdLock.Unlock()

	this.command = cmd
}

func (this *SessionInfo) StartRecord(fileName string) {

	if fileName == "" {
		fileName = this.createRecordFileName()
	}

	this.record = fileName

	ucall, ok := this.call[this.uCallId]
	if ok {
		ucall.StartRecord(this.record)
		logs.Debug("[%v] 启动录音成功", this.sessionId)
	} else {
		for _, c := range this.call {
			if false == c.AnswerTime.IsZero() {
				c.StartRecord(this.record)
				logs.Debug("[%v] 启动录音成功", this.sessionId)
				return
			}
		}
		logs.Debug("[%v] 启动录音失败，未找到呼叫信息", this.sessionId, this.uCallId)
	}

	return
}

func (this *SessionInfo) HoldTheCall() {

	err := fclient.SetNoHangUpAfterUnbridge(this.uCallId)
	if err != nil {
		logs.Error("[%v] hold the call err:%v", this.sessionId, err)
	} else {
		logs.Debug("[%v] 开启坐席挂机，不断开会话", this.sessionId)
	}
}

type DTMF_ARGS struct {
	KeyStop    bool   //按键停止播放音乐
	EndKey     string //按键停止收集
	MaxKey     int    //最多收取按键个数,0为一直接收
	TimeOut    int    //超时时间
	KeyTimeOut int    //按键间隔时间
	MediaFile  string //放音文件
	PlayTimes  int
}

func (this *SessionInfo) isDestroyed() bool {

	return this.bDestroy
}

func (this *SessionInfo) destroyDo(reason interface{}) {

	if this.bDestroy {
		return
	}

	logs.Debug("[%v]destroy status.set to destroy", this.sessionId)

	this.destroyTime = time.Now()
	this.bDestroy = true

	go func() {

		for _, call := range this.call {
			call.ErrHangUp(reason)
		}

		logs.Info("[%v] 会话销毁....", this.sessionId)
	}()

	return
}

func (this *SessionInfo) createRecordFileName() string {

	data := time.Now().Format("20050102")
	dir := "/data/record/" + data

	return fmt.Sprintf("%s/%s-%s-%s", dir,
		this.sessionId, this.caller, this.callee)
}

func (this *SessionInfo) Answered() {
	this.answerTime = time.Now()
}

func CreateSessionCallIn(appId, mainCallId string, uCall *call.CallInfo,
	cb chan *CallBackData) (ss *SessionInfo) {

	sessionId := fmt.Sprintf("%s-%s", mainCallId, CALL_TYPE_IN)
	v, ok := gSessions.Load(sessionId)
	if !ok {
		ss = &SessionInfo{
			caller:       uCall.Caller,
			callee:       uCall.Callee,
			display:      uCall.Callee,
			startTime:    uCall.StartTime,
			sessionId:    sessionId,
			callType:     CALL_TYPE_IN,
			appId:        appId,
			CbChan:       cb,
			satisfaction: "-1",
			call:         make(map[string]*call.CallInfo),
			evChan:       make(chan interface{}, 100),
		}
		ss.call[uCall.CallId()] = uCall
		ss.uCallId = uCall.CallId()
		gSessions.Store(sessionId, ss)

		//发送呼入通知
		ss.CallInRpt()

		//call绑定session
		uCall.BindSessionOnly(sessionId, ss.evChan)
		go ss.eventRoutine()

		uCall.Answer()
	} else {
		ss = v.(*SessionInfo)
	}
	return ss
}

func (this *SessionInfo) SetCaller(caller string) {
	this.caller = caller
}

func (this *SessionInfo) SetCallee(callee string) {
	this.callee = callee
}

func (this *SessionInfo) StoreCalls(call *call.CallInfo) {

	this.call[call.CallId()] = call
}

func (this *SessionInfo) IsEnd() bool {

	if this.hangCount == len(this.call) {
		return true
	}

	return false
}

func (this *SessionInfo) satisfactionReset() {
	this.satisfaction = "0"
}

func (this *SessionInfo) GetServiceId() string {

	return this.serviceId
}

type detail struct {
	Caller     string `json:"caller"`
	Callee     string `json:"callee"`
	ServiceId  string `json:"serviceId"`
	IsUser     bool   `json:"isUser"`
	IsPstn     bool   `json:"isPstn"`
	CallTime   string `json:"callTime"`
	AnswerTime string `json:"answerTime"`
	Dutation   int    `json:"dutation"`
	SipCode    string `json:"sipCode"`
}

type queTraceInfo struct {
	QueId     int    `json:"skillId"`   //入队技能组Id
	EnqueTime string `json:"enqueTime"` //入队时间
}

func (this *SessionInfo) PlayAndGetKeySimple(maxKey int, playFile string) {

	args := call.DTMF_ARGS{
		MediaFile: playFile,
		MaxKey:    maxKey,
	}

	if args.EndKey == "" {
		args.EndKey = "#"
	}

	if args.MaxKey == 0 {
		args.MaxKey = 1
	}

	if args.TimeOut == 0 {
		args.TimeOut = 30
	}

	if args.PlayTimes == 0 {
		args.PlayTimes = 1
	}

	ucall, ok := this.call[this.uCallId]
	if ok {
		ucall.CmdGetKeys(args)
	}
}

func (this *SessionInfo) PlayAndGetKey(input DTMF_ARGS) {

	args := call.DTMF_ARGS{
		MediaFile: input.MediaFile,
		MaxKey:    input.MaxKey,
	}

	if input.EndKey == "" {
		args.EndKey = "#"
	}

	if input.MaxKey == 0 {
		args.MaxKey = 1
	}

	if input.TimeOut == 0 {
		args.TimeOut = 30
	}

	if input.PlayTimes == 0 {
		args.PlayTimes = 1
	}

	ucall, ok := this.call[this.uCallId]
	if ok {
		ucall.CmdGetKeys(args)
	}
}

func (this *SessionInfo) hangupCall(callId string, reason interface{}) {

	if call, ok := this.call[callId]; ok {

		call.ErrHangUp(reason)
	}
}
